package com.ruoyi.location.repository;

import com.ruoyi.location.repository.dao.QuickReportDao;
import com.ruoyi.location.repository.generator.entity.QuickReportLocation;
import com.ruoyi.location.repository.generator.entity.QuickReportLocationExample;
import com.ruoyi.location.repository.generator.entity.QuickReportRoomName;
import com.ruoyi.location.repository.generator.entity.QuickReportRoomNameExample;
import com.ruoyi.location.repository.generator.mapper.QuickReportLocationMapper;
import com.ruoyi.location.repository.generator.mapper.QuickReportRoomNameMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.*;

@Repository
public class QuickReportRepository {
    @Autowired
    private QuickReportLocationMapper quickReportLocationMapper;
    @Autowired
    private QuickReportRoomNameMapper quickReportRoomNameMapper;
    @Autowired
    private QuickReportDao quickReportDao;

    /**
     * 插入数据到quickReportLocation，同时去重插入到quickReportRoomName
     * @param quickReportLocation 位置数据
     * @return 插入结果
     */
    public int insertQuickReportLocation(QuickReportLocation quickReportLocation) {
        // 插入位置数据
        int result = quickReportLocationMapper.insertSelective(quickReportLocation);

        // 检查是否已存在相同的room和name组合
        QuickReportRoomNameExample example = new QuickReportRoomNameExample();
        example.createCriteria()
                .andRoomEqualTo(quickReportLocation.getRoom())
                .andNameEqualTo(quickReportLocation.getName());

        List<QuickReportRoomName> existingRecords = quickReportRoomNameMapper.selectByExample(example);

        // 如果不存在相同的room和name组合，则插入到quickReportRoomName表
        if (existingRecords.isEmpty()) {
            QuickReportRoomName roomName = new QuickReportRoomName();
            roomName.setRoom(quickReportLocation.getRoom());
            roomName.setName(quickReportLocation.getName());
            roomName.setCtime(new Date());
            quickReportRoomNameMapper.insert(roomName);
        }

        return result;
    }

    /**
     * 根据room查找每个name的最新的数据，并返回list
     * @param room 房间号
     * @return 每个name的最新数据列表
     */
    public List<QuickReportLocation> selectLatestByRoomGroupByName(String room) {
        List<QuickReportLocation> result = new ArrayList<>();

        // 1. 先从quickReportRoomName表中查询指定room下的所有name
        QuickReportRoomNameExample roomNameExample = new QuickReportRoomNameExample();
        roomNameExample.createCriteria().andRoomEqualTo(room);
        List<QuickReportRoomName> roomNames = quickReportRoomNameMapper.selectByExample(roomNameExample);

        // 2. 遍历每个name，调用quickReportDao查询最新记录
        for (QuickReportRoomName roomName : roomNames) {
            QuickReportLocation latestLocation = quickReportDao.selectLatestByRoomAndName(
                    roomName.getRoom(), roomName.getName());
            if (latestLocation != null) {
                result.add(latestLocation);
            }
        }

        return result;
    }

    /**
     * 根据room查找name的指定范围点位
     * @param room 房间名称
     * @param dayType today：当天， today-1：昨天，today-2：前天，today-3：3天前 以此类推
     * @return Map<String, List<QuickReportLocation>> key为用户名，value为该用户在指定日期的所有位置点
     */
    public Map<String, List<QuickReportLocation>> listLocationsByRoom(String room, String dayType) {
        Map<String, List<QuickReportLocation>> result = new HashMap<>();

        // 1. 先从quickReportRoomName表中查询指定room下的所有name
        QuickReportRoomNameExample roomNameExample = new QuickReportRoomNameExample();
        roomNameExample.createCriteria().andRoomEqualTo(room);
        List<QuickReportRoomName> roomNames = quickReportRoomNameMapper.selectByExample(roomNameExample);

        // 2. 解析dayType并计算目标日期范围
        Date[] dateRange = parseDayType(dayType);
        Date startDate = dateRange[0]; // 当天00:00:00
        Date endDate = dateRange[1];   // 当天23:59:59

        // 3. 遍历每个name，查询指定日期范围内的所有位置点
        for (QuickReportRoomName roomName : roomNames) {
            String userName = roomName.getName();

            // 构建查询条件：room + name + 日期范围
            QuickReportLocationExample locationExample = new QuickReportLocationExample();
            locationExample.createCriteria()
                    .andRoomEqualTo(room)
                    .andNameEqualTo(userName)
                    .andCtimeGreaterThanOrEqualTo(startDate)
                    .andCtimeLessThanOrEqualTo(endDate);

            // 按时间正序排列
            locationExample.setOrderByClause("ctime ASC");

            // 查询该用户在指定日期的所有位置点
            List<QuickReportLocation> userLocations = quickReportLocationMapper.selectByExample(locationExample);

            // 坐标点位过多，进行简单去重处理
            List<QuickReportLocation> optimizedLocations = simpleDeduplicate(userLocations);
            result.put(userName, optimizedLocations);
        }

        return result;
    }

    /**
     * 解析dayType字符串，返回对应日期的开始和结束时间
     * @param dayType today：当天， today-1：昨天，today-2：前天，today-3：3天前 以此类推
     * @return Date数组，[0]为开始时间(00:00:00)，[1]为结束时间(23:59:59)
     */
    private Date[] parseDayType(String dayType) {
        Calendar calendar = Calendar.getInstance();

        // 解析dayType
        if ("today".equals(dayType)) {
            // 当天，不需要减天数
        } else if (dayType.startsWith("today-")) {
            // 解析today-N格式
            try {
                String dayStr = dayType.substring(6); // 去掉"today-"前缀
                int daysAgo = Integer.parseInt(dayStr);
                calendar.add(Calendar.DAY_OF_MONTH, -daysAgo);
            } catch (NumberFormatException e) {
                // 如果解析失败，默认为当天
                // 可以记录日志或抛出异常
            }
        } else {
            // 不支持的格式，默认为当天
            // 可以记录日志或抛出异常
        }

        // 设置开始时间：当天00:00:00
        Calendar startCalendar = (Calendar) calendar.clone();
        startCalendar.set(Calendar.HOUR_OF_DAY, 0);
        startCalendar.set(Calendar.MINUTE, 0);
        startCalendar.set(Calendar.SECOND, 0);
        startCalendar.set(Calendar.MILLISECOND, 0);

        // 设置结束时间：当天23:59:59
        Calendar endCalendar = (Calendar) calendar.clone();
        endCalendar.set(Calendar.HOUR_OF_DAY, 23);
        endCalendar.set(Calendar.MINUTE, 59);
        endCalendar.set(Calendar.SECOND, 59);
        endCalendar.set(Calendar.MILLISECOND, 999);

        return new Date[]{startCalendar.getTime(), endCalendar.getTime()};
    }

    /**
     * 简单的坐标去重处理
     * 策略：
     * 1. 只处理连续相同经纬度的点位
     * 2. 连续相同的点位：保留第一个和最后一个，中间每5个保留1个
     * 3. 逻辑简单，性能高效
     */
    private List<QuickReportLocation> simpleDeduplicate(List<QuickReportLocation> locations) {
        if (locations == null || locations.size() <= 3) {
            System.out.println("[简单去重] 点位数量过少，无需去重。原始点位数: " + (locations == null ? 0 : locations.size()));
            return locations; // 点位太少，直接返回
        }

        int originalSize = locations.size();
        String userName = locations.get(0).getName();
        System.out.println("[简单去重] 开始处理用户 " + userName + " 的坐标去重，原始点位数: " + originalSize);

        List<QuickReportLocation> result = new ArrayList<>();
        result.add(locations.get(0)); // 保留第一个点
        System.out.println("[简单去重] 保留起始点: " + formatLocationInfo(locations.get(0)));

        int duplicateGroupCount = 0; // 重复坐标组数
        int totalDuplicatePoints = 0; // 总重复点位数

        int i = 1;
        while (i < locations.size()) {
            QuickReportLocation current = locations.get(i);
            QuickReportLocation previous = result.get(result.size() - 1);

            // 检查坐标是否相同（精度到小数点后6位，约1米精度）
            if (isSameLocation(current, previous)) {
                duplicateGroupCount++;

                // 找到连续相同坐标的区间
                List<QuickReportLocation> sameGroup = new ArrayList<>();
                int j = i;
                while (j < locations.size() && isSameLocation(locations.get(j), previous)) {
                    sameGroup.add(locations.get(j));
                    j++;
                }

                totalDuplicatePoints += sameGroup.size();

                System.out.println("[简单去重] 发现重复坐标组 " + duplicateGroupCount +
                    ", 坐标: (" + String.format("%.6f", previous.getLatitude()) + ", " + String.format("%.6f", previous.getLongitude()) +
                    "), 重复点位数: " + sameGroup.size() +
                    ", 时间跨度: " + formatLocationInfo(sameGroup.get(0)) +
                    " ~ " + formatLocationInfo(sameGroup.get(sameGroup.size() - 1)));

                int beforeSize = result.size();

                // 简单策略：保留第一个和最后一个，中间每5个保留1个
                if (sameGroup.size() <= 2) {
                    // 少于等于2个，全部保留
                    result.addAll(sameGroup);
                    System.out.println("[简单去重] 重复点位≤2个，全部保留: " + sameGroup.size() + " 个");
                } else {
                    // 多于2个，保留第一个、最后一个，中间每5个保留1个
                    result.add(sameGroup.get(0)); // 保留第一个

                    // 中间每5个保留1个
                    int middleCount = 0;
                    for (int k = 5; k < sameGroup.size() - 1; k += 5) {
                        result.add(sameGroup.get(k));
                        middleCount++;
                    }

                    result.add(sameGroup.get(sameGroup.size() - 1)); // 保留最后一个

                    int keptCount = 2 + middleCount; // 首尾 + 中间保留的
                    double compressionRate = (1.0 - (double)keptCount / sameGroup.size()) * 100;
                    System.out.println("[简单去重] 重复点位>2个，保留策略: 首尾各1个 + 中间每5个保留1个(" + middleCount + "个) = 共保留" + keptCount + "个" +
                        " (压缩率: " + String.format("%.1f", compressionRate) + "%)");
                }

                int afterSize = result.size();
                System.out.println("[简单去重] 重复坐标组 " + duplicateGroupCount + " 处理完成，新增点位: " + (afterSize - beforeSize) + " 个");

                i = j; // 跳到下一个不同坐标的点
            } else {
                // 坐标不同，直接添加
                result.add(current);
                i++;
            }
        }

        int finalSize = result.size();
        double totalCompressionRate = (1.0 - (double)finalSize / originalSize) * 100;

        System.out.println("[简单去重] 用户 " + userName + " 去重完成! " +
            "原始点位: " + originalSize +
            ", 最终点位: " + finalSize +
            ", 总压缩率: " + String.format("%.1f", totalCompressionRate) + "%" +
            ", 重复坐标组数: " + duplicateGroupCount +
            ", 总重复点位数: " + totalDuplicatePoints);

        return result;
    }

    /**
     * 判断两个位置是否相同
     * @param loc1 位置1
     * @param loc2 位置2
     * @return 是否相同位置
     */
    private boolean isSameLocation(QuickReportLocation loc1, QuickReportLocation loc2) {
        if (loc1 == null || loc2 == null) {
            return false;
        }

        // 精度到小数点后4位，约100米精度
        double latDiff = Math.abs(loc1.getLatitude() - loc2.getLatitude());
        double lngDiff = Math.abs(loc1.getLongitude() - loc2.getLongitude());

        return latDiff < 0.0001 && lngDiff < 0.0001;
    }

    /**
     * 格式化位置信息，用于日志输出
     * @param location 位置信息
     * @return 格式化后的字符串
     */
    private String formatLocationInfo(QuickReportLocation location) {
        if (location == null) {
            return "null";
        }

        // 格式化时间为 HH:mm:ss
        String timeStr = "";
        if (location.getCtime() != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(location.getCtime());
            timeStr = String.format("%02d:%02d:%02d",
                cal.get(Calendar.HOUR_OF_DAY),
                cal.get(Calendar.MINUTE),
                cal.get(Calendar.SECOND));
        }

        return String.format("%s(%.6f,%.6f)",
            timeStr,
            location.getLatitude(),
            location.getLongitude());
    }

}
